package mobi.weq.util;

import mobi.weq.model.Observation;

public class GridUtil {

	public static void main(String[] args) {
		int[] coords = coordsToGridIndex(56.031617728001414,
				-2.8757937562500047, 4);
		gridIndexToCoords(coords[0], coords[1], 4);
		// System.out.format("%.3f%n", Math.PI);
		// EmissionZone[] highEmissionZone = { new EmissionZone(4, 4, 7),
		// new EmissionZone(2, 3, 11), new EmissionZone(1, 3, 2) };
		// createHeatmap(5, 5, highEmissionZone);

	}

	public static void getGridInBounds() {

	}

	public static int[] coordsToGridIndex(double lat, double lng, int zoom) {

		long multiple = (long) Math.pow(2, zoom);

		// grid index : 0,0 to 180, 360
		// adjust shifted origin
		lat += 90;
		lng += 180;

		int gridRow = (int) (lat / 0.0001);
		int gridColumn = (int) (lng / 0.0001);
		System.out.println(gridRow + "," + gridColumn);
		return new int[] { gridRow, gridColumn };
	}

	public static double[] gridIndexToCoords(int row, int col, int zoom) {
		long multiple = (long) Math.pow(2, zoom);

		// grid index : 0,0 to 180, 360
		// adjust shifted origin
		double lat = row * 0.0001;
		double lng = col * 0.0001;

		lat -= 90;
		lng -= 180;

		System.out.println(lat + "," + lng);
		return new double[] { lat, lng };
	}

	public static double meanOfAdjacentAndItself(double[][] map, int row,
			int col) {
		int[] rows = { -1, 0, 1 };
		int[] columns = { -1, 0, 1 };
		double sum = map[row][col];
		int count = 1;
		for (int i = 0; i < rows.length; i++) {
			for (int j = 0; j < columns.length; j++) {
				int r = row + rows[i];
				int c = col + columns[j];
				if (r >= 0 && r < map.length && c >= 0 && c < map[0].length) {
					sum += map[r][c];
					count++;
				}
			}
		}

		return sum / count;
	}

	public static void printGrid(double[][] heatmap) {
		for (int i = 0; i < heatmap.length; i++) {
			System.out.println();
			for (int j = 0; j < heatmap[i].length; j++) {
				System.out.format("\t%.2f", heatmap[i][j]);
			}
		}
	}

	public static void normalize(double[][] map) {
		double[] range = getRange(map);

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				map[i][j] = 10 * (map[i][j] - range[0]) / (range[1] - range[0]);
				// map[i][j] = Math.round(map[i][j]);
			}
		}
	}

	public static double[] getRange(double[][] map) {
		double[] range = { Double.MAX_VALUE, Double.MIN_NORMAL };

		int MIN = 0;
		int MAX = 1;

		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (map[i][j] < range[MIN]) {
					range[MIN] = map[i][j];
				}

				if (map[i][j] > range[MAX]) {
					range[MAX] = map[i][j];
				}

			}
		}
		return range;
	}

	public static double[][] createHeatmap(int row, int col,
			EmissionZone[] highEmissionZone) {

		double[][] heatmap = new double[row][col];
		double[][] intermediates = new double[row][col];

		for (int i = 0; i < heatmap.length; i++) {
			for (int j = 0; j < heatmap[i].length; j++) {
				heatmap[i][j] = 0;
			}
		}

		for (int i = 0; i < highEmissionZone.length; i++) {
			heatmap[highEmissionZone[i].row][highEmissionZone[i].col] = highEmissionZone[i].aqi;
		}

		printGrid(heatmap);

		System.out.println();
		System.out.println();
		System.out.println();

		int passes = 10;
		for (int k = 0; k < passes; k++) {
			// copying to intermediates
			for (int i = 0; i < heatmap.length; i++) {
				for (int j = 0; j < heatmap[i].length; j++) {
					intermediates[i][j] = heatmap[i][j];
				}
			}

			for (int i = 0; i < heatmap.length; i++) {
				for (int j = 0; j < heatmap[i].length; j++) {
					heatmap[i][j] = meanOfAdjacentAndItself(intermediates, i, j);

				}
			}
		}

		// printGrid(heatmap);
		normalize(heatmap);
		printGrid(heatmap);

		return heatmap;
	}

	public static Observation[][] getRandomGridWithPollution(int hour) {
		return null;
	}
}

class EmissionZone {
	public int row, col;
	public double aqi;

	public EmissionZone(int row, int col, double aqi) {
		this.row = row;
		this.col = col;
		this.aqi = aqi;
		// TODO Auto-generated constructor stub
	}
}
